package com.wzz.download.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.util.List;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.StatFs;
import android.util.Log;
/**
 * 下载文件
 * com.jh.android.download.DownUtils
 * @author 祁元美 <br/>
 * create at 2011-8-25 下午1:26:19
 */
public class DownUtils {

  private static final String TAG = "TestDown";

  private static SharedPreferences preferences;
  private static String PRE_NAME = "DownFile";
  private HttpUtils httpConnection;//连接http服务器    
  private int hasRead;//服务器的字节数累加  
  private int index;//下载进度
  private int reConnectionCount;//重新连接次数
  private Message message;
  private String fPath = null;
  private long fileCompleteSize;
  public static boolean  ISENDTHREAD= false; //线程是否停止


  public DownUtils(Context context){
    httpConnection = new HttpUtils();
    fPath = Environment.getExternalStorageDirectory().getPath()+"/";
    preferences = context.getSharedPreferences(PRE_NAME,Context.MODE_PRIVATE);
    //判断preferences 是否包含有此key值的值，没有，则创建
    if(!preferences.contains("fileSizeComplete")){
      initSharedPreferenceFile();
    }
  }
  /**
   * 創建初始值为0
   */
  private void initSharedPreferenceFile(){
    preferences.edit().putLong("fileSizeComplete", 0).commit();   
  }


  /**
   * 设置网络链接次数
   * @param reConnectionCount 网络连接失败重新连接次数
   */
  public void setReConnectionCount(int reConnectionCount) {
    this.reConnectionCount = reConnectionCount;
  }

  /**
   * 供外部调用的下载方法
   * @param destUrl 下载文件连接
   * @param fileName 自定义文件名称
   * @param filePath 自定义文件存放位置
   * @throws Exception
   */
  public void downLoadFile(final List<String> list,final String fileName ,
      final String filePath ,final Handler handler){

    if(list != null && list.size() != 0){
      startDownFileThread(list,fileName,filePath,handler);
    }else{
      handlerException(handler,"down load url cant't be null");
      return ;
    }

  }
  private InputStream getHttpInputStream(String url,Handler handler){
    InputStream inputStream = null; //连接服务器后返回的输入流
    fileCompleteSize = preferences.getLong("fileSizeComplete", 0);//获取上次文件下载大小
    try {
      inputStream = httpConnection.connectHttp(url, fileCompleteSize);
    } catch (Exception e) {
      inputStream = conHttpException(url,fileCompleteSize,handler);
      setHandlerFileComplete("",handler);
    }
    return inputStream;
  }
  /**
   * 開啟下載文件線程
   * @param list
   * @param fileName
   * @param filePath
   * @param handler
   */

  private void startDownFileThread(final List<String> list,final String fileName ,
      final String filePath ,final Handler handler){
    new Thread(new Runnable(){
      public void run() {
        Looper.prepare();
        try{
          traverseUrl(list,handler,fileName,filePath);
        } finally{
          closeHttpConnect();
        }
      }
    }).start();
  }
  /**
   * 關閉網絡連接
   */
  private void closeHttpConnect(){
    if(httpConnection != null){
      httpConnection.getHttpConnection().disconnect();
    }
  }
  /**
   * 遍歷URL
   */
  private void traverseUrl(final List<String> list,final Handler handler,final String fileName,final String filePath){
    for(int i =0;i < list.size(); i++){
      if(ISENDTHREAD == false){//如果線程沒停止
        InputStream inputStream  = getHttpInputStream(list.get(i),handler);
        String path = getFileNameAndPath(fileName , filePath);
        /**判断存贮空间是否够*/
        long fileTotalSize =  httpConnection.getFileSizeDown();          
        if(fileTotalSize < getSDCardAvailableAt(fPath)){
          try {
            writeDownFile(inputStream, path, fileCompleteSize,fileTotalSize,handler);
          } catch (IOException e) {
            handlerException(handler,e+"文件写入异常");//文件写入异常
            setHandlerFileComplete("",handler);
            continue;
          }
        }else{
          handlerException(handler,"Not enough storage space");
          return;
        }
      }
    }
  }

  /**
   * 判斷用戶是否給出自定義文件名和存放路徑后，確定最後文件保存位置
   * @param fileName
   * @param filePath
   * @return
   */
  private String getFileNameAndPath(final String fileName,String filePath){
    String fName = httpConnection.getFileNameDown();
    /**如果自定义文件名不为空则赋值给中间变量fName*/
    if(fileName != null && !"".equalsIgnoreCase(fileName.trim())){
      fName = fileName;
    }
    if(filePath !=null && !"".equalsIgnoreCase(filePath.trim())){
      fPath = filePath;
    }
    return fPath+fName;
  }

  /**
   * 网络链接异常时，重新連接三次
   * @param destUrl 下载地址
   * @param fileCompleteSize 任务目前完成字节数
   * @param handler 如果三次仍链接失败抛出异常
   * @return 连接成功返回的字符串
   */
  private InputStream conHttpException(String destUrl,long fileCompleteSize,Handler handler ){
    InputStream inputStream = null;
    try{
      if(reConnectionCount == 0){reConnectionCount = 3;}
      for(int i = 0;i < reConnectionCount; i++){
        inputStream = httpConnection.connectHttp(destUrl, fileCompleteSize);
      }
    }catch(IOException e){
      handlerException(handler ,"重新连接失敗");
    }
    return inputStream;
  }
  /**
   * 保存文件
   * @param inputStream 服务器给的输入流
   * @param fileNameDown 文件名称
   * @param bytes 从哪开始下的字节数
   * @param fileSize 文件总大小
   * @throws FileNotFoundException 
   * @throws IOException
   */
  private void writeDownFile(InputStream inputStream ,String fileNameDown ,
      long bytes ,long fileSize ,Handler handler) throws FileNotFoundException,IOException{
    if(inputStream != null){
      byte[] buffer = new byte[1024*4]; 
      File file = new File(fileNameDown );
      RandomAccessFile  randomDown = new RandomAccessFile(file,"rw");
      Log.d(TAG, "random down"+randomDown+"");
      randomDown.seek(bytes);
      Log.d(TAG, "random bytes"+bytes+"");
      Log.d(TAG, "random  inputStream"+inputStream+"");
      int read; 
      while((read = inputStream.read(buffer)) > 0){ 
        randomDown.write(buffer,0,read);//写文件
        hasRead += read;
        index = (int) ((int)(hasRead*100)/fileSize); 
        if(handler != null){
          sendHandlerIndexFile(index,handler);
        }
        if(index == 100){
          setHandlerFileComplete(fileNameDown,handler);
          index = 0;
          hasRead = 0;
        }
        /**将累加的下载字节数存进SharedPreferences*/
        preferences.edit().putLong("fileSizeComplete", hasRead).commit();
      }
      randomDown.close();
      preferences.edit().clear().commit();//都收完之后清空sharepreferences
    }

  }

  //文件下载完成或者下载文件过程中出现异常等情况，给主线程发送Handler
  private void setHandlerFileComplete(String fileNameDown,Handler handler){
    Log.d(TAG, "SEND HANDLER COMPLETE");
    message = new Message();   
    message.what = 3; 
    message.obj = fileNameDown;
    handler.sendMessage(message);
  }
  //给界面发送进度
  private void sendHandlerIndexFile(int index,Handler handler){
    message = new Message();    
    message.obj = index;
    message.what = 1;    
    handler.sendMessage(message);
  }
  //抛异常给用户
  private void handlerException(Handler handler,String e){
    message = new Message();
    message.what = 2;
    message.obj = e;
    handler.sendMessage(message);
  }
  /**
   * 判断是否有可用的网络链接
   * @return 网络链接是否可用
   */
  public  static boolean isNetworkAvailable(Context ctx) {  
    Context context = ctx.getApplicationContext(); 
    ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
    if(connectivity != null){
      NetworkInfo[] info = connectivity.getAllNetworkInfo();     
      if (info != null) {         
        for (int i = 0; i<info.length; i++) {            
          if (info[i].getState() == NetworkInfo.State.CONNECTED) {  
            return true;  
          }         
        }      
      } 
    }
    return false;
  } 

  /**
   * 是否有SDCARD
   * @return
   */
  public static boolean avaiableMedia(){   
    String status = Environment.getExternalStorageState();   
    if(status.equals(Environment.MEDIA_MOUNTED)){  
      return true;   
    }else {
      return false;   
    }   
  }  
  /**
   * 获得当前路径可用空间字节数
   * @param path
   * @return
   */
  private  long getSDCardAvailableAt(String path) {
    StatFs sfs = new StatFs(path);
    long availableCount = sfs.getAvailableBlocks();
    long blockSizea = sfs.getBlockSize();
    return (availableCount * blockSizea);
  }
}
